package com.iplant.base.utils.sql;

import com.alibaba.fastjson.JSON;
import com.iplant.base.po.*;
import com.iplant.base.po.enums.DBCutTableModes;
import com.iplant.base.po.enums.DBEnumType;
import com.iplant.base.po.enums.DBSchemas;
import com.iplant.base.po.enums.ExceptionTypes;
import com.iplant.base.utils.BaseConfigConstans;
import com.iplant.base.utils.annotation.field.DBFieldValue;
import com.iplant.base.utils.annotation.condition.DBConditionValue;
import com.iplant.base.utils.annotation.join.multi.select.DBJoinMultiSelectValue;
import com.iplant.base.utils.annotation.join.DBJoinValue;
import com.iplant.base.utils.annotation.po.DBBasePO;
import com.iplant.base.utils.cache.CacheUtils;
import com.iplant.base.utils.general.CalendarTool;
import com.iplant.base.utils.general.LockHelper;
import com.iplant.base.utils.general.StringUtils;
import com.iplant.base.utils.serializer.CloneTool;
import com.iplant.base.utils.sql.orm.DMLTool;
import com.iplant.base.utils.sql.orm.ORMUtils;
import com.iplant.base.utils.sql.orm.POUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import javax.swing.text.StyledEditorKit;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @author xiuto
 */
@Slf4j
public class BaseDAO {

    private ShrisJdbcTemplate shrisJdbcTemplate;

    protected LockHelper mLockHelper = null;

    protected Class<? extends BasePO> Clazz;

    private boolean IsSetConfig = false;

    public BaseDAO() {
        shrisJdbcTemplate = DBDruidHelper.getInstance().getTemplate(this.SQLType);
    }

    public BaseDAO(String wTableName) {
        if (StringUtils.isNotEmpty(wTableName)) {
            this.TableName = wTableName;
            shrisJdbcTemplate = DBDruidHelper.getInstance().getTemplate(this.SQLType);
        }
    }

    public BaseDAO(String wTableName, DBEnumType wType) {
        this.TableName = wTableName;
        this.SQLType = wType;
        shrisJdbcTemplate = DBDruidHelper.getInstance().getTemplate(wType);
    }

    public BaseDAO(String wTableName, DBEnumType wType, DBSchemas wSchemasType) {
        this.TableName = wTableName;
        this.SQLType = wType;
        this.SchemasType = wSchemasType;
        shrisJdbcTemplate = DBDruidHelper.getInstance().getTemplate(wType);
    }


    public BaseDAO(Class<? extends BasePO> wClazz) {
        Clazz = wClazz;
        setPOConfig(wClazz);

        shrisJdbcTemplate = DBDruidHelper.getInstance().getTemplate(this.SQLType);

    }


    protected void Init() {
        Clazz = POUtils.GetInstance().getDBBaseDAOClass(getClass());
        setPOConfig(Clazz);
        if (shrisJdbcTemplate == null) {
            shrisJdbcTemplate = DBDruidHelper.getInstance().getTemplate(this.SQLType);
        }
    }

    protected DBEnumType SQLType = DBEnumType.getEnumType(BaseConfigConstans.DBServerType);

    protected DBSchemas SchemasType = DBSchemas.Basic;

    public BaseDAO(ShrisJdbcTemplate shrisJdbcTemplate) {
        this.shrisJdbcTemplate = shrisJdbcTemplate;
        this.SQLType = shrisJdbcTemplate.DBType;
    }

    public BaseDAO(DBEnumType wSQLTypes) {
        this.shrisJdbcTemplate = DBDruidHelper.getInstance().getTemplate(wSQLTypes);
        this.SQLType = wSQLTypes;
    }

    public synchronized int Execute(List<String> wSqlList) {

        return shrisJdbcTemplate.Execute(wSqlList);
    }


    protected Object GetMapObject(Map<String, Object> wMap, String wKey) {
        Object wResult = null;
        try {
            if (wMap == null || wMap.size() < 1 || wKey == null || wKey.isEmpty()) {
                return wResult;
            }

            if (wMap.containsKey(wKey)) {
                wResult = wMap.get(wKey);
            }

        } catch (Exception e) {
            e.printStackTrace();
            log.error(e.toString());
        }
        return wResult;
    }


    private <T extends BasePO> String GetCodePrefix(String wCodePrefix, T wBasePo) {
        String wResult = wCodePrefix;
        try {
            StringBuffer wStringBuffer = new StringBuffer("");

            Matcher wMatcher = Pattern.compile("\\{\\:(?<Column>[^\\}]+)\\}", Pattern.CASE_INSENSITIVE).matcher(
                    wCodePrefix);

            Map<String, Field> collect = POUtils.GetInstance().GetFieldMap(wBasePo.getClass());

            Field wField;
            while (wMatcher.find()) {

                if (collect.containsKey(wMatcher.group("Column"))) {
                    wField = collect.get(wMatcher.group("Column"));
                } else {
                    wField = null;
                }

                if (wField == null || wField.get(wBasePo) == null) {
                    wMatcher.appendReplacement(wStringBuffer, "");
                    continue;
                }
                wMatcher.appendReplacement(wStringBuffer, StringUtils.parseString(wField.get(wBasePo)));
            }
            wMatcher.appendTail(wStringBuffer);
            wResult = wStringBuffer.toString();

            wMatcher = Pattern.compile("\\{(?<Column>[^\\}]+)\\}", Pattern.CASE_INSENSITIVE).matcher(
                    wResult);
            wStringBuffer.setLength(0);

            Calendar wNow = Calendar.getInstance();

            while (wMatcher.find()) {
                wMatcher.appendReplacement(wStringBuffer, StringUtils.CalendarFormat(wNow, wMatcher.group("Column")));
            }
            wMatcher.appendTail(wStringBuffer);
            wResult = wStringBuffer.toString();
        } catch (Exception e) {
            log.error(e.toString());
        }
        return wResult;
    }

    protected String DMLChange(String wMySqlString, DBEnumType wSQLTypeField) {
        return DMLTool.GetInstance().DMLChange(wMySqlString, wSQLTypeField);
    }

    protected String DMLChange(String wMySqlString) {
        return DMLTool.GetInstance().DMLChange(wMySqlString, SQLType);
    }

    protected List<Map<String, Object>> QueryForList(String wSQL, Map<String, Object> wParamMap) {

        return shrisJdbcTemplate.queryForList(wSQL, wParamMap);

    }

    protected List<Map<String, Object>> QueryForList(
            String wSQL, Map<String, Object> wParamMap, Pagination wPagination, String wTableName,
            List<String> wTableNames) {

        return shrisJdbcTemplate.queryForList(wSQL, wParamMap, wPagination, wTableName, wTableNames);

    }

    protected List<Map<String, Object>> queryForList(String wSQL, Map<String, Object> wParamMap) {

        return shrisJdbcTemplate.queryForList(wSQL, wParamMap);

    }

    protected List<Map<String, Object>> queryForList(
            String wSQL, Map<String, Object> wParamMap, Pagination wPagination, String wTableName,
            List<String> wTableNames) {

        return shrisJdbcTemplate.queryForList(wSQL, wParamMap, wPagination, wTableName, wTableNames);

    }

    protected List<Map<String, Object>> queryForList(
            String wSQL, Map<String, Object> wParamMap, String wTableName, List<String> wTableNames) {

        return shrisJdbcTemplate.queryForList(wSQL, wParamMap, null, wTableName, wTableNames);

    }


    protected List<Map<String, Object>> queryForList(
            String wSQL, Map<String, Object> wParamMap, Pagination wPagination) {

        return shrisJdbcTemplate.queryForList(wSQL, wParamMap, wPagination);

    }


    protected Map<String, Object> QueryForObject(String wSQL, Map<String, Object> wParamMap) {

        return shrisJdbcTemplate.queryForMap(wSQL, wParamMap);
    }

    protected Map<String, Object> queryForMap(String wSQL, Map<String, Object> wParamMap) {

        return shrisJdbcTemplate.queryForMap(wSQL, wParamMap);
    }

    protected <T> List<T> QueryForList(String wSQL, Map<String, Object> wParamMap, Class<T> clazz) {

        List<Map<String, Object>> wQueryResultList = shrisJdbcTemplate.queryForList(wSQL, wParamMap);

        return JSON.parseArray(StringUtils.toJSONString(wQueryResultList), clazz);

    }

    protected <T> List<T> QueryForList(
            String wSQL, Map<String, Object> wParamMap, Pagination wPagination, Class<T> clazz) {

        List<Map<String, Object>> wQueryResultList = shrisJdbcTemplate.queryForList(wSQL, wParamMap, wPagination);

        return JSON.parseArray(StringUtils.toJSONString(wQueryResultList), clazz);

    }


    protected <T> T queryForObject(String wSQL, Map<String, Object> wParamMap, Class<T> clazz) {

        return shrisJdbcTemplate.queryForObject(wSQL, wParamMap, clazz);

    }

    /**
     * Select数据量查询数据
     *
     * @param wSQL      查询sql语句 用:冒号定义参数
     * @param wParamMap sql参数集
     * @param clazz     返回数据类型 注意sql返回的数据需与实体类型相匹配 不准用简单类型
     * @return 查询得到的数据
     */
    protected <T> T QueryForObject(String wSQL, Map<String, Object> wParamMap, Class<T> clazz) {

        Map<String, Object> wQueryResult = shrisJdbcTemplate.queryForMap(wSQL, wParamMap);

        return JSON.parseObject(StringUtils.toJSONString(wQueryResult), clazz);

    }

    /**
     * 获取最大主键值
     *
     * @param wTableName
     * @param wKey
     * @return
     */
    protected int GetMaxPrimaryKey(String wTableName, String wKey) {
        int wResult = 0;
        if (StringUtils.isEmpty(wTableName) || StringUtils.isEmpty(wKey)) {
            return wResult;
        }

        String wSQL = StringUtils.Format("Select Max({0}) as ID from {1} ;", wKey, wTableName);
        List<Map<String, Object>> wQueryResultList = this.queryForList(wSQL, new HashMap<>());

        for (Map<String, Object> wSqlDataReader : wQueryResultList) {
            wResult = StringUtils.parseInt(wSqlDataReader.get("ID"));
        }
        return wResult;
    }

    /**
     * 根据相同前缀创建同前缀的最大新编码
     *
     * @param wTableName 全表名
     * @param wPrefix    编码前缀
     * @param wCodeKey   编码数据表字段名 如：Code
     * @param wD         序列号长度 如wD=4代表0001-9999
     * @return 同前缀的最大编码
     */
    public <T extends BasePO> String CreateMaxCode(String wTableName, String wPrefix, String wCodeKey, int wD,
                                                   T wBasePo, int wIndex) {

        int wMaxNum = 0;
        if (wD <= 0 || wD >= 10) {
            wD = 7;
        }

        if (wPrefix == null) {
            wPrefix = "";
        }
        wPrefix = this.GetCodePrefix(wPrefix, wBasePo);

        if (StringUtils.isEmpty(wTableName) || StringUtils.isEmpty(wCodeKey)) {


            return StringUtils.Format("{0}{1}", wPrefix, String.format("%0" + wD + "d", wMaxNum + 1 + wIndex));
        }

        String wSQLText = StringUtils.Format("select Max(SUBSTRING_INDEX(t.{1},''{2}'',-1) + 0 ) as ItemCount  " +
                        "  from {0} t where t.ID>0 AND t.{1} like :Name   ;", wTableName, wCodeKey,
                wPrefix);
        if (StringUtils.isEmpty(wPrefix)) {

            wSQLText = StringUtils.Format("select Max(t.{1} + 0 ) as ItemCount  from {0} t  where t.ID>0 ;", wTableName,
                    wCodeKey);
        }
        Map<String, Object> wParams = new HashMap<>();
        wParams.put("Name", wPrefix + "%");

        List<Map<String, Object>> wQueryResultList = this.queryForList(wSQLText, wParams);

        for (Map<String, Object> wSqlDataReader : wQueryResultList) {
            wMaxNum = StringUtils.parseInt(wSqlDataReader.get("ItemCount"));
        }

        return StringUtils.Format("{0}{1}", wPrefix, String.format("%0" + wD + "d", wMaxNum + 1 + wIndex));

    }


    /**
     * 根据相同前缀创建同前缀的最大数字
     *
     * @param wTableName
     * @param wPrefix
     * @param wIntKey
     * @param wD
     * @return
     */
    public int CreateMaxInt(String wTableName, int wPrefix, String wIntKey, int wD) {

        int wMaxNum = 0;

        if (StringUtils.isEmpty(wTableName) || StringUtils.isEmpty(wIntKey)) {
            return wMaxNum + 1;
        }
        if (wD <= 0 || wD >= 10) {
            wD = 7;
        }

        String wSQLText = StringUtils.Format("select (Max(t.{1}) + 0 ) as ItemCount  " +
                "  from {0} t where t.ID>0  and  t.{1}>= :PrefixMin and t.{1}< :PrefixMax;", wTableName, wIntKey);
        if (wPrefix <= 0) {
            wSQLText = StringUtils.Format("select Max(t.{1} + 0 ) as ItemCount  from {0} t  where t.ID>0 ;", wTableName,
                    wIntKey);
        }

        Map<String, Object> wParams = new HashMap<>();
        wParams.put("PrefixMin", wPrefix * Math.pow(10, wD));
        wParams.put("PrefixMax", (wPrefix + 1) * Math.pow(10, wD));

        List<Map<String, Object>> wQueryResultList = this.queryForList(wSQLText, wParams);

        for (Map<String, Object> wSqlDataReader : wQueryResultList) {
            wMaxNum = StringUtils.parseInt(wSqlDataReader.get("ItemCount"));
        }

        return wMaxNum + 1;

    }


    /**
     * 执行SQL语句
     *
     * @param wSQL                待执行SQL语句
     * @param wSqlParameterSource SQL语句中的参数源结构
     * @param keyHolder           主键
     * @return 影响条目数
     */
    public int update(String wSQL, SqlParameterSource wSqlParameterSource, KeyHolder keyHolder) {
        return shrisJdbcTemplate.update(wSQL, wSqlParameterSource, keyHolder);
    }

    /**
     * 插入数据通用接口
     *
     * @param wSQL                待执行Insert SQL语句
     * @param wSqlParameterSource SQL语句中的参数源结构
     * @return 插入返回的主键ID
     */
    public int insert(String wSQL, SqlParameterSource wSqlParameterSource) {
        KeyHolder keyHolder = new GeneratedKeyHolder();
        shrisJdbcTemplate.update(wSQL, wSqlParameterSource, keyHolder);
        return keyHolder.getKey().intValue();
    }

    /**
     * 插入数据通用接口
     *
     * @param wSQL  待执行Insert SQL语句
     * @param wData SQL语句中的参数
     * @return 插入返回的主键ID
     */
    public int insert(String wSQL, Map<String, Object> wData) {
        SqlParameterSource wSqlParameterSource = new MapSqlParameterSource(wData);
        KeyHolder keyHolder = new GeneratedKeyHolder();
        shrisJdbcTemplate.update(wSQL, wSqlParameterSource, keyHolder);
        return keyHolder.getKey().intValue();
    }

    /**
     * 执行SQL语句
     *
     * @param wSQL                待执行SQL语句
     * @param wSqlParameterSource SQL语句中的参数源结构
     * @return 影响条目数量
     */
    public int update(String wSQL, SqlParameterSource wSqlParameterSource) {
        return shrisJdbcTemplate.update(wSQL, wSqlParameterSource);
    }

    /**
     * 执行SQL语句
     *
     * @param wSQL  待执行SQL语句
     * @param wData SQL语句中的参数
     * @return 影响条目数量
     */
    public int update(String wSQL, Map<String, Object> wData) {
        return shrisJdbcTemplate.update(wSQL, wData);
    }


    public int update(String wSQL, Map<String, Object> wData, DBCutTableModes wCutTableMode) {
        if (wCutTableMode != DBCutTableModes.Default) {

            List<String> wTableNameL = this.GetCutTableName();

            if (wTableNameL.size() > 0) {

                int wResult = 0;
                for (String item : wTableNameL) {
                    wResult += this.Update(wSQL.replace(this.TableName, item), wData);
                }
                return wResult;
            }

        }
        return shrisJdbcTemplate.update(wSQL, wData);
    }

    public int update(String wSQL, Map<String, Object> wData, Calendar wMin, Calendar wMax) {
        if (CutTableMode != DBCutTableModes.Default) {

            List<String> wTableNameL = this.GetCutTableName(wMin, wMax);

            if (wTableNameL.size() > 0) {

                int wResult = 0;
                for (String item : wTableNameL) {
                    wResult += this.Update(wSQL.replace(this.TableName, item), wData);
                }
                return wResult;
            }

        }
        return shrisJdbcTemplate.update(wSQL, wData);
    }

    /**
     * 执行SQL语句
     *
     * @param wSQL 待执行SQL语句
     * @return 影响条目数量
     */
    public int update(String wSQL) {
        return shrisJdbcTemplate.update(wSQL, new HashMap<>());
    }

    /**
     * 插入数据通用接口
     *
     * @param wTableName 全表名 如 SchemasName.tableName
     * @param wData      待插入数据项
     * @return 插入返回的主键ID
     */
    public int Insert(String wTableName, Map<String, Object> wData) {

        if (StringUtils.isEmpty(wTableName) || wData == null || wData.size() == 0) {
            return 0;
        }

        if (CutTableMode != DBCutTableModes.Default) {
            this.CreateTable();
        }

        List<String> wColumns = new ArrayList<>();

        List<String> wPData = new ArrayList<>();

        for (String wColumn : wData.keySet()) {
            wColumns.add(wColumn);
            wPData.add(":" + wColumn);
        }

        String wSQL = StringUtils.Format("insert into {0} ({1}) values ({2});", wTableName,
                StringUtils.Join(",", wColumns), StringUtils.Join(",", wPData));

        KeyHolder keyHolder = new GeneratedKeyHolder();

        SqlParameterSource wSqlParameterSource = new MapSqlParameterSource(wData);
        shrisJdbcTemplate.update(wSQL, wSqlParameterSource, keyHolder);

        return keyHolder.getKey() == null ? 0 : keyHolder.getKey().intValue();
    }

    /**
     * 插入数据通用接口
     *
     * @param wTableName 全表名 如 SchemasName.tableName
     * @param wData      待插入数据项
     * @return 插入返回的主键ID
     */
    public int Import(String wTableName, List<Map<String, Object>> wData) {

        if (StringUtils.isEmpty(wTableName) || wData == null || wData.size() == 0) {
            return 0;
        }
        wData.removeIf(p -> p == null || p.size() == 0);


        Map<String, Object> wFirst = wData.get(0);


        List<String> wColumns = new ArrayList<>(wFirst.keySet());

        List<String> wPData = new ArrayList<>();

        List<String> wTData = new ArrayList<>();
        for (Map<String, Object> wDatum : wData) {
            for (String wColumn : wColumns) {
                if (!wDatum.containsKey(wColumn)) {
                    wTData.add("''");
                    continue;
                }
                wTData.add("'" + StringUtils.parseString(wDatum.get(wColumn)) + "'");
            }

            wPData.add(StringUtils.Join(",", wTData));
        }

        String wSQL = StringUtils.Format("insert into {0} ({1}) values ({2});", wTableName,
                StringUtils.Join(",", wColumns), StringUtils.Join("),(", wPData));

        SqlParameterSource wSqlParameterSource = new MapSqlParameterSource(new HashMap<>());

        return shrisJdbcTemplate.update(wSQL, wSqlParameterSource);
    }


    /**
     * 更新数据通用接口
     *
     * @param wTableName      全表名 如 SchemasName.tableName
     * @param wPrimaryKey     主键名
     * @param wData           待更新数据项
     * @param wOtherCondition 其他条件
     * @return 更新条目数
     */
    public int Update(String wTableName, String wPrimaryKey, Map<String, Object> wData, String... wOtherCondition) {

        if (StringUtils.isEmpty(wTableName) || StringUtils.isEmpty(wPrimaryKey) || wData == null || wData.size() <= 1 ||
                !wData.containsKey(wPrimaryKey)) {
            return 0;
        }

        List<String> wColumns = new ArrayList<>();

        for (String wColumn : wData.keySet()) {
            if (wPrimaryKey.equals(wColumn)) {
                continue;
            }
            wColumns.add(wColumn + " = :" + wColumn);
        }


        String wCondition = wPrimaryKey + " = :" + wPrimaryKey;
        String wSQL = StringUtils.Format("Update {0} set {1} where {2} {3} ;", wTableName,
                StringUtils.Join(",", wColumns), wCondition,
                (wOtherCondition == null || wOtherCondition.length == 0) ? "" :
                        StringUtils.JoinArray(" ", wOtherCondition));

        return shrisJdbcTemplate.update(wSQL, wData);

    }


    /**
     * 更新数据通用接口
     *
     * @param wTableName      全表名 如 SchemasName.tableName
     * @param wData           待更新数据项
     * @param wConditionData  更新数据项条件数据
     * @param wOtherCondition 其他条件
     * @return 更新条目数
     */
    public int Update(
            String wTableName, Map<String, Object> wData, Map<String, Object> wConditionData,
            String... wOtherCondition) {

        if (StringUtils.isEmpty(wTableName) || wData == null || wData.size() == 0) {
            return 0;
        }

        List<String> wColumns = new ArrayList<>();

        for (String wColumn : wData.keySet()) {
            wColumns.add(wColumn + " = :" + wColumn);
        }

        List<String> wConditionColumns = new ArrayList<>();

        /**
         * 避免条件与变更数据重复 引入参数后缀 _ConditionName
         */
        Map<String, Object> wConditionData_T = new HashMap<>();
        if (wConditionData != null && wConditionData.size() > 0) {
            for (String wColumn : wConditionData.keySet()) {
                wConditionColumns.add(wColumn + " = :" + wColumn + "_ConditionName");
                wConditionData_T.put(wColumn + "_ConditionName", wConditionData.get(wColumn));
            }
        }
        String wSQL;
        if (wConditionColumns.size() > 0) {

            wSQL = StringUtils.Format("Update {0} set {1} where {2} {3}   ;", wTableName,
                    StringUtils.Join(",", wColumns), StringUtils.Join(" and ", wConditionColumns),
                    (wOtherCondition == null || wOtherCondition.length == 0) ? "" :
                            StringUtils.JoinArray(" ", wOtherCondition));
        } else {
            wSQL = StringUtils.Format("Update {0} set {1} where 1=1  {2}   ;", wTableName,
                    StringUtils.Join(",", wColumns),
                    (wOtherCondition == null || wOtherCondition.length == 0) ? "" :
                            StringUtils.JoinArray(" ", wOtherCondition));
        }

        Map<String, Object> wParams = new HashMap<>();
        wParams.putAll(wData);
        wParams.putAll(wConditionData_T);

        return shrisJdbcTemplate.update(wSQL, wParams);

    }


    /**
     * 更新数据通用接口
     *
     * @param wData           待更新数据项
     * @param wConditionData  更新数据项条件数据
     * @param wOtherCondition 其他条件
     * @return 更新条目数
     */
    public int Update(Map<String, Object> wData, Map<String, Object> wConditionData, String... wOtherCondition) {

        if (CutTableMode != DBCutTableModes.Default) {

            List<String> wTableNameL = this.GetCutTableName();

            if (wTableNameL.size() > 0) {

                int wResult = 0;
                for (String item : wTableNameL) {
                    wResult += this.Update(this.getTableName(item), wData, wConditionData, wOtherCondition);
                }
                return wResult;
            }

        }
        return this.Update(this.getTableName(), wData, wConditionData, wOtherCondition);

    }


    /**
     * 删除数据记录通用接口
     *
     * @param wTableName      全表名 如 SchemasName.tableName
     * @param wData           删除数据项判断条件
     * @param wOtherCondition 其他条件
     * @return 删除条目数
     */
    public int Delete(String wTableName, Map<String, Object> wData, String... wOtherCondition) {

        if (StringUtils.isEmpty(wTableName) || wData == null || wData.size() == 0) {
            return 0;
        }

        List<String> wColumns = new ArrayList<>();

        for (String wColumn : wData.keySet()) {

            wColumns.add(wColumn + " = :" + wColumn);
        }

        String wSQL = StringUtils.Format("Delete from {0} where {1} {2};", wTableName,
                StringUtils.Join(" and ", wColumns), (wOtherCondition == null || wOtherCondition.length <= 0) ? "" :
                        StringUtils.JoinArray(" ", wOtherCondition));

        return shrisJdbcTemplate.update(wSQL, wData);

    }

    /**
     * 删除数据记录通用接口
     *
     * @param wData           删除数据项判断条件
     * @param wOtherCondition 其他条件
     * @return 删除条目数
     */
    public int Delete(Map<String, Object> wData, String... wOtherCondition) {
        if (CutTableMode != DBCutTableModes.Default) {

            List<String> wTableNameL = this.GetCutTableName();

            if (wTableNameL.size() > 0) {

                int wResult = 0;
                for (String item : wTableNameL) {
                    wResult += this.Delete(this.getTableName(item), wData, wOtherCondition);
                }
                return wResult;
            }

        }
        return this.Delete(this.getTableName(), wData, wOtherCondition);

    }

    public int DeleteBase(String wTableName, String wMustCondition, String... wOtherCondition) {

        if (StringUtils.isEmpty(wMustCondition))
            return 0;

        String wSQL = this.DeleteSql(wTableName, wMustCondition, wOtherCondition);

        return shrisJdbcTemplate.update(wSQL, new HashMap<>());
    }

    public String DeleteSql(String wTableName, String wMustCondition, String... wOtherCondition) {

        if (StringUtils.isEmpty(wMustCondition))
            return "";

        return StringUtils.Format("Delete from {0} where  {1}  {2};", wTableName,
                wMustCondition, (wOtherCondition == null || wOtherCondition.length == 0) ? "" :
                        StringUtils.JoinArray(" ", wOtherCondition));
    }

    /**
     * 删除数据记录通用接口
     *
     * @param wOtherCondition 其他条件
     * @return 删除条目数
     */
    public int Delete(String wMustCondition, String... wOtherCondition) {

        if (CutTableMode != DBCutTableModes.Default) {

            List<String> wTableNameL = this.GetCutTableName();

            if (wTableNameL.size() > 0) {
                List<String> wSql = new ArrayList<>();
                for (String item : wTableNameL) {
                    wSql.add(this.DeleteSql(this.getTableName(item), wMustCondition, wOtherCondition));
                }
                return this.Execute(wSql);
            }

        }
        return this.DeleteBase(this.getTableName(), wMustCondition, wOtherCondition);
    }


    /**
     * 批量执行SQL
     *
     * @param wSqlList 批量SQL语句
     */
    public void ExecuteSqlTransaction(List<String> wSqlList) {
        try {
            String wSQL = "";
            for (String wString : wSqlList) {

                wSQL = this.DMLChange(wString, SQLType);
                shrisJdbcTemplate.update(wSQL, new HashMap<>());
            }
        } catch (Exception e) {
            log.error(e.toString());
        }
    }

    /**
     * 执行SQL
     *
     * @param wSqlString SQL语句
     */
    public void ExecuteSqlTransaction(String wSqlString) {
        try {
            String wSQL = this.DMLChange(wSqlString, SQLType);
            shrisJdbcTemplate.update(wSQL, new HashMap<>());

        } catch (Exception e) {
            e.printStackTrace();
            log.error(e.toString());
        }
    }

    /**
     * 更新数据表通用接口
     *
     * @param wSqlString SQL语句
     * @param wParamMap  SQL语句中的参数
     * @return 更新的条目数
     */
    public int Update(String wSqlString, Map<String, Object> wParamMap) {
        return shrisJdbcTemplate.update(wSqlString, wParamMap);
    }

    /**
     * 插入数据通用接口
     *
     * @param wParamMapList 数据项列表
     * @return 插入的条目数
     */
    public int Insert(List<Map<String, Object>> wParamMapList) {

        return this.Insert(this.getTableName(Calendar.getInstance()), wParamMapList);
    }

    /**
     * 插入数据通用接口
     *
     * @param wTableName    全表名 如 SchemasName.tableName
     * @param wParamMapList 待插入的数据项列表
     * @return 插入的条目数
     */
    public synchronized int Insert(String wTableName, List<Map<String, Object>> wParamMapList) {

        if (wParamMapList == null || wParamMapList.size() == 0 || StringUtils.isEmpty(wTableName)) {
            return 0;
        }

        List<String> wColumns = wParamMapList.get(0).keySet().stream().collect(Collectors.toList());

        StringBuilder wStringBuilder = null;
        List<String> wDataString = new ArrayList<>();
        String wKey = "";
        for (Map<String, Object> wData : wParamMapList) {
            wStringBuilder = new StringBuilder();
            wStringBuilder.append("(");
            for (int i = 0; i < wColumns.size(); i++) {

                if (i != 0) {
                    wStringBuilder.append(",");
                }

                wKey = wColumns.get(i);

                if (!wData.containsKey(wKey)) {
                    wStringBuilder.append("''");
                } else {
                    if (wData.get(wKey) instanceof Calendar) {
                        wStringBuilder.append("'" + StringUtils.parseCalendarToString((Calendar) wData.get(wKey),
                                "yyyy/MM/dd HH:mm:ss") + "'");
                    } else if (wData.get(wKey) instanceof Date) {
                        wStringBuilder.append(
                                "'" + StringUtils.parseDateToString((Date) wData.get(wKey), "yyyy/MM/dd HH:mm:ss") +
                                        "'");
                    } else {
                        wStringBuilder.append("'" + wData.get(wKey) + "'");
                    }

                }
            }

            wStringBuilder.append(")");
            wDataString.add(wStringBuilder.toString());

        }

        String wSQL = StringUtils.Format("insert into {0} ({1}) values {2};", wTableName,
                StringUtils.Join(",", wColumns), StringUtils.Join(",", wDataString));

        return shrisJdbcTemplate.update(wSQL, new HashMap<>());
    }

    /**
     * 更新数据表通用接口
     *
     * @param wPrimaryKey     主键名
     * @param wParamMapList   待更新的数据项列表
     * @param wOtherCondition 其他条件
     * @return 更新的条目数
     */
    public int Update(String wPrimaryKey, List<Map<String, Object>> wParamMapList, String... wOtherCondition) {

        return this.Update(this.getTableName(), wPrimaryKey, wParamMapList, wOtherCondition);
    }

    /**
     * 更新数据表通用接口
     *
     * @param wTableName      全表名 如 SchemasName.tableName
     * @param wPrimaryKey     主键名
     * @param wParamMapList   待更新的数据项列表
     * @param wOtherCondition 其他条件
     * @return 更新的条目数
     */
    public synchronized int Update(
            String wTableName, String wPrimaryKey, List<Map<String, Object>> wParamMapList, String... wOtherCondition) {
        int wResult = 0;
        if (wParamMapList == null || wParamMapList.size() == 0) {
            return wResult;
        }
        for (Map<String, Object> wData : wParamMapList) {
            wResult += this.Update(wTableName, wPrimaryKey, wData, wOtherCondition);
        }

        return wResult;
    }

    protected String TableName = "";
    private String IndexName = "";
    private DBBasePO dBBasePO = null;
    protected DBCutTableModes CutTableMode = DBCutTableModes.Default;

    /**
     * 设置数据表名
     *
     * @param wTableName 表名
     */
    protected void setTableName(String wTableName) {
        TableName = wTableName;
    }

    /**
     * 获取DAO设置的数据库类型对应的名称
     *
     * @return 数据库名
     */
    protected String getDBName() {
        return SchemasType.getDBName(this.SQLType);
    }


    /**
     * 获取全表名 如 SchemasName.tableName  使用DAO中的SchemasType与SQLType
     *
     * @return 全表名
     */
    protected String getTableName(Calendar wCreateTime) {
        return SchemasType.getTBName(SQLType, POUtils.GetInstance().GetTableName(this.CutTableMode, wCreateTime,
                TableName));
    }


    protected String getTableName(BasePO wBasePO) {

        if (wBasePO == null)
            return SchemasType.getTBName(SQLType, TableName);

        //根据时间获取表名称
        return SchemasType.getTBName(SQLType, POUtils.GetInstance().GetTableName(this.CutTableMode,
                wBasePO.CreateTime, TableName));
    }

    protected String getDeleteTableName(DBBasePO wDBBasePO) {
        return wDBBasePO.Schemas().getTBName(wDBBasePO.DBType(), POUtils.GetInstance().GetDeleteTableName(wDBBasePO.TableName()));
    }

    /**
     * 获取全表名 如 SchemasName.tableName  使用DAO中的SchemasType与SQLType
     *
     * @return 全表名
     */
    protected String getTableName() {
        if (CutTableMode == DBCutTableModes.Default)
            return SchemasType.getTBName(SQLType, TableName);
        return getTableName(Calendar.getInstance());
    }

    /**
     * 获取DAO中设置的IndexName的值
     *
     * @return
     */
    protected String getIndexName() {
        return IndexName;
    }

    /**
     * 获取实体类上DBBasePO注解IndexName的值 默认返回本类的简称SimpleName
     *
     * @param clazz 实体类class  如xx.class
     * @param <T>   实体类对象类型 必须继承于BasePO
     * @return IndexName的值
     */
    protected <T> String getIndexName(Class<T> clazz) {
        DBBasePO wDBBasePO = POUtils.GetInstance().getDBBasePO(clazz);
        if (wDBBasePO == null || StringUtils.isEmpty(wDBBasePO.IndexName())) {
            return clazz.getSimpleName();
        } else {
            return wDBBasePO.IndexName();
        }
    }


    /**
     * 获取全表名 如 SchemasName.tableName
     *
     * @param dbBasePO 实体类上的DBBasePO注解
     * @return 全表名 如 SchemasName.tableName
     */
    public String getTableName(DBBasePO dbBasePO) {
        if (dbBasePO.DBType() == DBEnumType.Default) {
            return dbBasePO.Schemas().getTBName(SQLType, dbBasePO.TableName());
        } else {
            return dbBasePO.Schemas().getTBName(dbBasePO.DBType(), dbBasePO.TableName());
        }
    }

    /**
     * 获取全表名 如 SchemasName.tableName
     *
     * @param wTableName 表名
     * @return 全表名 如 SchemasName.tableName
     */
    protected String getTableName(String wTableName) {
        return SchemasType.getTBName(SQLType, wTableName);
    }

    protected String getTableName(DBSchemas wSchemasType, String wTableName) {
        return wSchemasType.getTBName(SQLType, wTableName);
    }

    /**
     * 将实体类的DBBasePO注解中的配置设置到数据操作类XXDAO
     *
     * @param clazz 实体类class  如xx.class
     */
    private void setPOConfig(Class<? extends BasePO> clazz) {

        if (clazz == null) {
            return;
        }
        if (IsSetConfig) {
            return;
        }
        IsSetConfig = true;
        mLockHelper = LockHelper.getLock(clazz);

        DBBasePO wDBBasePO = POUtils.GetInstance().getDBBasePO(clazz);


        if (wDBBasePO != null) {

            dBBasePO = wDBBasePO;

            if (this.SQLType != wDBBasePO.DBType() || shrisJdbcTemplate == null) {
                this.SQLType = wDBBasePO.DBType();
                shrisJdbcTemplate = DBDruidHelper.getInstance().getTemplate(this.SQLType);
            }

            if (wDBBasePO.Schemas() != this.SchemasType) {
                this.SchemasType = wDBBasePO.Schemas();
            }
            if (StringUtils.isNotEmpty(wDBBasePO.TableName())) {
                this.TableName = wDBBasePO.TableName();
            }
            this.CutTableMode = wDBBasePO.CutTableMode();
            //判断表是否存在，不存在则创建表
            if (wDBBasePO.AutoCreateTable()) {
                POUtils.GetInstance().CreateTable(clazz, wDBBasePO, shrisJdbcTemplate, wDBBasePO.AllowDeleteTable());
            }
        }
    }

    public List<String> GetCutTableName() {
        return GetCutTableName(true);
    }

    public List<String> GetCutTableName(boolean wIsReversed) {
        return GetCutTableName(null, null, true);
    }

    public List<String> GetCutTableName(Calendar wStartTime, Calendar wEndTime, boolean wIsReversed) {
        if (CutTableMode != DBCutTableModes.Default) {
            List<String> wResult = POUtils.GetInstance().GetCutTableName(this.SchemasType.getDBName(), this.TableName
                    , this.SQLType, shrisJdbcTemplate, wIsReversed);


            return POUtils.GetInstance().FilterTableName(CutTableMode, wStartTime, wEndTime, this.TableName, wResult);
        }

        return StringUtils.parseListArgs(this.TableName);
    }

    public List<String> GetCutTableName(Calendar wStartTime, Calendar wEndTime) {

        return GetCutTableName(wStartTime, wEndTime, true);
    }


    public void CreateTable(DBBasePO wDBBasePO) {
        POUtils.GetInstance().CreateTable(Clazz, wDBBasePO, shrisJdbcTemplate);
    }

    public void CreateTable() {
        if (dBBasePO == null)
            dBBasePO = POUtils.GetInstance().getDBBasePO(Clazz);
        if (dBBasePO == null)
            return;
        POUtils.GetInstance().CreateTable(Clazz, dBBasePO, shrisJdbcTemplate);
    }

    //创建删除表
    //将删除数据记录到删除表中


    /**
     * 删除实体类
     *
     * @param wLoginUser 用户
     * @param wBasePO    实体类示例
     * @param wErrorCode 错误码
     * @param <T>        实体类对象类型 必须继承于BasePO
     * @return 删除数据条目数
     */
    public <T extends BasePO> int DeletePO(BaseUser wLoginUser, T wBasePO, OutResult<Integer> wErrorCode) {

        return this.DeletePO(wLoginUser, wBasePO, false, wErrorCode);
    }


    /**
     * 删除实体类
     *
     * @param wLoginUser 用户
     * @param wBasePO    实体类示例
     * @param wErrorCode 错误码
     * @param <T>        实体类对象类型 必须继承于BasePO
     * @return 删除数据条目数
     */
    public <T extends BasePO> int DeletePO(BaseUser wLoginUser, T wBasePO, boolean wIsSuper, OutResult<Integer> wErrorCode) {
        wErrorCode.set(0);
        int wResult = 0;
        try {

            if (wBasePO == null || wBasePO.ID <= 0) {
                wErrorCode.set(ExceptionTypes.Parameter.getValue());
                return wResult;
            }
            if (Clazz == null) {
                Clazz = wBasePO.getClass();
                setPOConfig(Clazz);
            }

            DBBasePO dbBasePO = POUtils.GetInstance().getDBBasePO(wBasePO.getClass());

            Map<String, Object> wParams = new HashMap<>();

            wParams.put("ID", wBasePO.ID);

            if (wIsSuper&& dbBasePO.AllowDeleteTable()) {

                this.InsertDeletePo(wLoginUser, wBasePO, wErrorCode);

                wResult = this.Delete(getTableName(wBasePO), wParams);

            } else if (dbBasePO == null || dbBasePO.Active()) {
                wResult = this.Delete(getTableName(wBasePO), wParams, " and Active=0 ");
            } else {
                wResult = this.Delete(getTableName(wBasePO), wParams);
            }

            List<DBJoinMultiSelectValue> dbJoinMultiSelectValueList =
                    POUtils.GetInstance().getDBJoinMultiSelectValueList(wBasePO.getClass());

            if (dbJoinMultiSelectValueList == null || dbJoinMultiSelectValueList.size() == 0)
                return wResult;


            Object obj = null;
            for (DBJoinMultiSelectValue dbJoinMultiSelectValue : dbJoinMultiSelectValueList) {

                obj = dbJoinMultiSelectValue.MainField.get(wBasePO);
                if (StringUtils.IsEmptyCondition(obj))
                    continue;


                wParams.clear();
                wParams.put(dbJoinMultiSelectValue.OutTableField, obj);
                ORMUtils.GetPoService(dbJoinMultiSelectValue.ItemClazz).Delete(wLoginUser,
                        wParams);
            }

        } catch (Exception ex) {
            log.error("BaseDelete", ex);
            wErrorCode.set(ExceptionTypes.DBSQL.getValue());
        }
        return wResult;
    }


    public <T extends BasePO> int DeletePOList(BaseUser wLoginUser, List<T> wBasePOList,
                                               OutResult<Integer> wErrorCode) {
        return this.DeletePOList(wLoginUser, wBasePOList, false, wErrorCode);
    }

    /**
     * 删除实体类
     *
     * @param wLoginUser  用户
     * @param wBasePOList 实体类示例
     * @param wErrorCode  错误码
     * @param <T>         实体类对象类型 必须继承于BasePO
     * @return 删除数据条目数
     */
    public <T extends BasePO> int DeletePOList(BaseUser wLoginUser, List<T> wBasePOList, boolean wIsSuper,
                                               OutResult<Integer> wErrorCode) {
        wErrorCode.set(0);
        int wResult = 0;
        try {

            if (wBasePOList == null || wBasePOList.size() == 0 || wBasePOList.get(0) == null) {
                wErrorCode.set(ExceptionTypes.Parameter.getValue());
                return wResult;
            }

            if (Clazz == null) {
                if (wBasePOList.get(0) != null) {
                    Clazz = wBasePOList.get(0).getClass();
                    setPOConfig(Clazz);
                } else {
                    wErrorCode.set(ExceptionTypes.Parameter.getValue());
                    return wResult;
                }
            }

            DBBasePO dbBasePO = POUtils.GetInstance().getDBBasePO(wBasePOList.get(0).getClass());

            List<Integer> wIDList =
                    wBasePOList.stream().filter(p -> p.ID > 0).map(p -> p.ID).distinct().collect(Collectors.toList());

            if (wIDList == null || wIDList.size() == 0) {
                return wResult;
            }
            if (wIsSuper&& dbBasePO.AllowDeleteTable()) {
                this.InsertDeletePo(wLoginUser, wBasePOList, wErrorCode);

                wResult = this.Delete(" ID  in (" + StringUtils.Join(",", wIDList) + ")");
            } else if (dbBasePO == null || dbBasePO.Active()) {
                wResult = this.Delete(" ID  in (" + StringUtils.Join(",", wIDList) + ")", " and Active=0 ");
            } else {
                wResult = this.Delete(" ID  in (" + StringUtils.Join(",", wIDList) + ")");
            }


            List<DBJoinMultiSelectValue> dbJoinMultiSelectValueList =
                    POUtils.GetInstance().getDBJoinMultiSelectValueList(wBasePOList.get(0).getClass());

            if (dbJoinMultiSelectValueList == null || dbJoinMultiSelectValueList.size() == 0)
                return wResult;

            List<Object> wValueList = new ArrayList<>();

            Object obj = null;
            Map<String, Object> wParams = new HashMap<>();

            for (DBJoinMultiSelectValue dbJoinMultiSelectValue : dbJoinMultiSelectValueList) {

                wValueList.clear();
                for (T t : wBasePOList) {
                    obj = dbJoinMultiSelectValue.MainField.get(t);
                    if (StringUtils.IsEmptyCondition(obj))
                        continue;
                    wValueList.add(obj);
                }
                if (wValueList.size() == 0)
                    continue;

                ORMUtils.GetPoService(dbJoinMultiSelectValue.ItemClazz).Delete(wLoginUser,
                        StringUtils.Format("{0} in (''{1}'')", dbJoinMultiSelectValue.OutTableField,
                                StringUtils.Join("','", wValueList)));

            }

        } catch (Exception ex) {
            log.error("BaseDelete", ex);
            wErrorCode.set(ExceptionTypes.DBSQL.getValue());
        }
        return wResult;
    }

    /**
     * 删除实体类记录  通过ID
     *
     * @param wLoginUser 用户
     * @param wBasePO    实体类示例
     * @param wDBSchemas 数据库名
     * @param wErrorCode 错误码
     * @param <T>        实体类对象类型 必须继承于BasePO
     */
    public <T extends BasePO> void DeletePO(
            BaseUser wLoginUser, T wBasePO, DBSchemas wDBSchemas, OutResult<Integer> wErrorCode) {
        wErrorCode.set(0);

        try {

            if (wBasePO == null || wBasePO.ID <= 0) {
                wErrorCode.set(ExceptionTypes.Parameter.getValue());
                return;
            }

            if (Clazz == null) {
                Clazz = wBasePO.getClass();
                this.setPOConfig(wBasePO.getClass());
            }


            DBBasePO dbBasePO = POUtils.GetInstance().getDBBasePO(wBasePO.getClass());


            Map<String, Object> wParams = new HashMap<>();

            wParams.put("ID", wBasePO.ID);
            if (dbBasePO == null || dbBasePO.Active()) {
                this.Delete(wDBSchemas.getTBName(SQLType, this.getTableName(wBasePO)), wParams, " and Active=0 ");
            } else {
                this.Delete(wDBSchemas.getTBName(SQLType, this.getTableName(wBasePO)), wParams);
            }

        } catch (Exception ex) {
            log.error("CustomerDelete", ex);
            wErrorCode.set(ExceptionTypes.DBSQL.getValue());
        }

    }


    public <T extends BasePO> int UpdateCheckPo(BaseUser wLoginUser, T wBasePO, OutResult<Integer> wErrorCode) {
        return this.UpdatePo(wLoginUser, wBasePO, true, wErrorCode);
    }

    public <T extends BasePO> int UpdatePo(BaseUser wLoginUser, T wBasePO, OutResult<Integer> wErrorCode) {
        return this.UpdatePo(wLoginUser, wBasePO, false, wErrorCode);
    }

    private <T extends BasePO> void InsertDeletePo(BaseUser wLoginUser, T wBasePO, OutResult<Integer> wErrorCode) {

        this.InsertDeletePo(wLoginUser, StringUtils.parseListArgs(wBasePO), wErrorCode);
    }

    private <T extends BasePO> void InsertDeletePo(BaseUser wLoginUser, List<T> wBasePOList, OutResult<Integer> wErrorCode) {

        try {
            if (wBasePOList == null) {
                wErrorCode.set(ExceptionTypes.Parameter.getValue());
                return;
            }
            if (wBasePOList.size() == 0)
                return;

            wBasePOList.removeIf(p -> p == null);

            if (wBasePOList.size() == 0)
                return;

            Class wClazz = wBasePOList.get(0).getClass();

            DBBasePO dbBasePO = POUtils.GetInstance().getDBBasePO(wClazz);
            if (dbBasePO == null || StringUtils.isEmpty(dbBasePO.TableName())) {
                log.error("DAO:" + wClazz.getName() +
                        ", Annotation DBBasePO undefined or TableName undefined!");
                wErrorCode.Result = ExceptionTypes.DBSQL.getValue();
                return;
            }
            Map<String, Object> wParams = POUtils.GetInstance().GetImportParam(wBasePOList.get(0), dbBasePO, 0,
                    wErrorCode);

            if (wErrorCode.Result != 0)
                return;
            List<Map<String, Object>> wData = new ArrayList<>();
            wData.add(wParams);
            if (wBasePOList.size() > 0) {
                wBasePOList.remove(0);
                wData.addAll(CloneTool.CloneArray(wBasePOList));
            }
            this.Import(getDeleteTableName(dbBasePO), wData);

        } catch (Exception ex) {
            log.error("InsertDeletePo", ex);
            wErrorCode.set(ExceptionTypes.DBSQL.getValue());
        }
    }

    /**
     * 修改/新增实体类记录 通过ID
     *
     * @param wLoginUser 用户
     * @param wBasePO    实体类示例
     * @param wErrorCode 错误码
     * @param <T>        实体类对象类型 必须继承于BasePO
     * @return 影响的数据条目数
     */
    public <T extends BasePO> int UpdatePo(BaseUser wLoginUser, T wBasePO, boolean wIsChecked,
                                           OutResult<Integer> wErrorCode) {
        int wRow = 0;
        wErrorCode.set(0);
        if (Clazz == null) {
            if (wBasePO != null) {
                Clazz = wBasePO.getClass();
                setPOConfig(Clazz);
            } else {
                wErrorCode.set(ExceptionTypes.Parameter.getValue());
                return wRow;
            }
        }
        synchronized (Clazz) {
            try {

                if (wBasePO == null) {
                    wErrorCode.set(ExceptionTypes.Parameter.getValue());
                    return wRow;
                }

                DBBasePO dbBasePO = POUtils.GetInstance().getDBBasePO(wBasePO.getClass());
                if (dbBasePO == null || StringUtils.isEmpty(dbBasePO.TableName())) {
                    log.error("DAO:" + wBasePO.getClass().getName() +
                            ", Annotation DBBasePO undefined or TableName undefined!");
                    wErrorCode.Result = ExceptionTypes.DBSQL.getValue();
                    return wRow;
                }

                if (dbBasePO.CheckName() != null && dbBasePO.CheckName().length > 0) {
                    BasePO wBasePOO = this.CheckPo(wLoginUser, wBasePO, wErrorCode);
                    if (wBasePOO.ID > 0) {
                        if (wBasePO.ID <= 0 && !wIsChecked) {
                            wBasePO.ID = wBasePOO.ID;
                        } else {
                            wErrorCode.set(ExceptionTypes.Duplication.getValue());
                            return wRow;
                        }
                    }

                }

                Map<String, Object> wParams = POUtils.GetInstance().GetUpdateParam(wBasePO, dbBasePO, this, 0,
                        wErrorCode);
                if (wErrorCode.Result != 0)
                    return wRow;

                if (wBasePO.ID > 0) {
                    wRow = this.Update(getTableName(wBasePO), dbBasePO.PrimaryKey(), wParams);
                } else {
                    wBasePO.ID = this.Insert(getTableName(wBasePO), wParams);
                    wRow = wBasePO.ID;
                }

                if (dbBasePO.Cache())
                    CacheUtils.SetOld(Clazz);


            } catch (Exception ex) {
                log.error("UpdatePo", ex);
                wErrorCode.set(ExceptionTypes.DBSQL.getValue());
            }

        }
        return wRow;

    }

    public <T extends BasePO> void UpdatePoList(BaseUser wLoginUser, List<T> wBasePOList,
                                                OutResult<Integer> wErrorCode) {
        this.UpdatePoList(wLoginUser, wBasePOList, true, false, wErrorCode);
    }

    public <T extends BasePO> void UpdatePoList(BaseUser wLoginUser, List<T> wBasePOList, boolean wIsAlone,
                                                boolean wIsChecked, OutResult<Integer> wErrorCode) {


        wErrorCode.set(0);
        if (wBasePOList == null || wBasePOList.size() == 0)
            return;
        if (Clazz == null) {
            if (wBasePOList.get(0) != null) {
                Clazz = wBasePOList.get(0).getClass();
                setPOConfig(Clazz);
            } else {
                wErrorCode.set(ExceptionTypes.Parameter.getValue());
                return;
            }
        }
        synchronized (Clazz) {

            try {

                if (wBasePOList.get(0) == null) {
                    wErrorCode.set(ExceptionTypes.Parameter.getValue());
                    return;
                }

                DBBasePO dbBasePO = POUtils.GetInstance().getDBBasePO(wBasePOList.get(0).getClass());
                if (dbBasePO == null || StringUtils.isEmpty(dbBasePO.TableName())) {
                    log.error("DAO:" + wBasePOList.get(0).getClass().getName() +
                            ", Annotation DBBasePO undefined or TableName undefined!");
                    wErrorCode.Result = ExceptionTypes.DBSQL.getValue();
                    return;
                }
                List<Map<String, Object>> wInsertList = new ArrayList<>();
                List<Map<String, Object>> wUpdateList = new ArrayList<>();
                List<Calendar> wUpdateDateList = new ArrayList<>();
                Map<String, Object> wParams;
                for (T wBasePO : wBasePOList) {
                    wBasePO.setUserInfo(wLoginUser);
                    if (dbBasePO.CheckName() != null && dbBasePO.CheckName().length > 0) {
                        BasePO wBasePOO = this.CheckPo(wLoginUser, wBasePO, wErrorCode);
                        if (wBasePOO.ID > 0) {
                            if (wBasePO.ID <= 0 && !wIsChecked) {
                                wBasePO.ID = wBasePOO.ID;
                            } else {
                                wErrorCode.set(ExceptionTypes.Duplication.getValue());
                                return;
                            }
                        }
                    }

                    wParams = POUtils.GetInstance().GetUpdateParam(wBasePO, dbBasePO, this, wInsertList.size(),
                            wErrorCode);
                    if (wErrorCode.Result != 0)
                        return;

                    if (wBasePO.ID > 0) {

                        wUpdateDateList.add(wBasePO.CreateTime);
                        wUpdateList.add(wParams);
                    } else {
                        if (wIsAlone) {
                            wBasePO.ID = this.Insert(getTableName(dbBasePO), wParams);
                        } else {
                            wInsertList.add(wParams);
                        }

                    }

                }
                this.Insert(getTableName(dbBasePO), wInsertList);

                for (int i = 0; i < wUpdateList.size(); i++) {
                    this.Update(getTableName(wUpdateDateList.get(i)), dbBasePO.PrimaryKey(), wUpdateList.get(i));
                }

                if (dbBasePO.Cache())
                    CacheUtils.SetOld(Clazz);

            } catch (Exception ex) {
                log.error("UpdatePoList", ex);
                wErrorCode.set(ExceptionTypes.DBSQL.getValue());
            }

        }
    }


    /**
     * 检查实体类数据是否重复
     *
     * @param wLoginUser 用户
     * @param wBasePO    实体类示例
     * @param wErrorCode 错误码
     * @param <T>        实体类对象类型 必须继承于BasePO
     * @return 重复的数据或空数据
     */
    private <T extends BasePO> BasePO CheckPo(BaseUser wLoginUser, T wBasePO, OutResult<Integer> wErrorCode) {
        BasePO wResult = new BasePO();

        try {
            if (wBasePO == null) {
                wErrorCode.set(ExceptionTypes.Parameter.getValue());
                return wResult;
            }
            DBBasePO dbBasePO = POUtils.GetInstance().getDBBasePO(wBasePO.getClass());

            if (dbBasePO.CheckName() == null || dbBasePO.CheckName().length <= 0) {
                return wResult;
            }

            List<String> wCheckNameList = StringUtils.parseList(dbBasePO.CheckName());
            if (wCheckNameList.size() == 0) {
                return wResult;
            }
            /**
             * Code自动生成 但是Code为空  即不用检查
             */
            if (wCheckNameList.size() == 1 && wCheckNameList.get(0).equalsIgnoreCase("Code") &&
                    dbBasePO.CodeAuto() && StringUtils.isEmpty(wBasePO.Code) &&
                    wBasePO.ID <= 0) {
                return wResult;
            }


            Map<String, Object> wParams = new HashMap<>();


            List<String> wColumnsList = new ArrayList<>();
            List<DBFieldValue> dbFieldList = POUtils.GetInstance().getDBField(dbBasePO.TableAsName(), wBasePO, dbBasePO,
                    true);
            List<String> wColumns;
            List<String> wCheckNameSingleList;
            for (String wCheckNames : wCheckNameList) {
                if (StringUtils.isEmpty(wCheckNames))
                    continue;

                wCheckNameSingleList = StringUtils.splitList(wCheckNames, ",");
                if (wCheckNameSingleList == null || wCheckNameSingleList.size() == 0)
                    continue;
                wColumns = new ArrayList<>();

                for (DBFieldValue dbFieldValue : dbFieldList) {
                    if (dbFieldValue.name.equals(dbBasePO.PrimaryKey())) {
                        wColumns.add(dbBasePO.PrimaryKey() + " != :" + dbBasePO.PrimaryKey());
                        wParams.put(dbFieldValue.name, dbFieldValue.getValue());
                    } else if (wCheckNameSingleList.contains(dbFieldValue.name)) {
                        wColumns.add(dbFieldValue.name + " = :" + dbFieldValue.name);
                        wParams.put(dbFieldValue.name, dbFieldValue.getValue());
                    }
                }
                if (wColumns.size() > 0)
                    wColumnsList.add(StringUtils.Join(" and ", wColumns));
            }

            List<String> wTableName = this.GetCutTableName();

            if (wTableName == null || wTableName.size() == 0)
                return wResult;

            String wSQLText;
            List<Map<String, Object>> wQueryResultList;
            for (String item : wTableName) {
                wSQLText = StringUtils.Format("Select * from {0} where ( {1} ) ", this.getTableName(item),
                        StringUtils.Join(") or (", wColumnsList));

                wQueryResultList = this.queryForList(wSQLText, wParams);
                for (Map<String, Object> wSqlDataReader : wQueryResultList) {
                    wResult.ID = StringUtils.parseInt(wSqlDataReader.get("ID"));
                    wResult.CreatorID = StringUtils.parseInt(wSqlDataReader.get("CreatorID"));
                    wResult.CreateTime = StringUtils.parseCalendar(wSqlDataReader.get("CreateTime"));
                    wResult.EditorID = StringUtils.parseInt(wSqlDataReader.get("EditorID"));
                    wResult.EditTime = StringUtils.parseCalendar(wSqlDataReader.get("EditTime"));
                    if (wSqlDataReader.containsKey("Active"))
                        wResult.Active = StringUtils.parseInt(wSqlDataReader.get("Active"));
                    if (wSqlDataReader.containsKey("Name"))
                        wResult.Name = StringUtils.parseString(wSqlDataReader.get("Name"));
                    if (wSqlDataReader.containsKey("Active"))
                        wResult.Active = StringUtils.parseInt(wSqlDataReader.get("Active"));
                }
            }

        } catch (Exception ex) {
            log.error("CheckPo", ex);
            wErrorCode.set(ExceptionTypes.DBSQL.getValue());
        }
        return wResult;
    }


    /**
     * 激活实体类数据
     *
     * @param wLoginUser 用户
     * @param wBasePO    实体类示例
     * @param wActive    激活状态
     * @param wErrorCode 错误码
     * @param <T>        实体类对象类型 必须继承于BasePO
     * @return 影响数据条目数
     */
    public <T extends BasePO> int ActivePO(
            BaseUser wLoginUser, T wBasePO, int wActive, OutResult<Integer> wErrorCode) {
        wErrorCode.set(0);
        int wResult = 0;
        try {

            if (wBasePO == null || wBasePO.ID <= 0) {
                wErrorCode.set(ExceptionTypes.Parameter.getValue());
                return wResult;
            }
            if (Clazz == null) {
                Clazz = wBasePO.getClass();
                this.setPOConfig(wBasePO.getClass());
            }
            DBBasePO dbBasePO = POUtils.GetInstance().getDBBasePO(wBasePO.getClass());
            if (dbBasePO != null && !dbBasePO.Active()) {
                wErrorCode.set(ExceptionTypes.Exception.getValue());
                return wResult;
            }

            Map<String, Object> wParams = new HashMap<>();

            wParams.put("ID", wBasePO.ID);
            wParams.put("EditorID", wLoginUser.getID());
            wParams.put("EditTime", Calendar.getInstance());

            wParams.put("Active", wActive);
            this.Update(getTableName(wBasePO), "ID", wParams);

        } catch (Exception ex) {
            log.error("ActivePO", ex);
            wErrorCode.set(ExceptionTypes.DBSQL.getValue());
        }
        return wResult;
    }


    public <T extends BasePO> int ActivePOList(
            BaseUser wLoginUser, List<T> wBasePOList, int wActive, OutResult<Integer> wErrorCode) {
        wErrorCode.set(0);
        int wResult = 0;
        try {

            if (wBasePOList == null || wBasePOList.size() == 0) {
                wErrorCode.set(ExceptionTypes.Parameter.getValue());
                return wResult;
            }

            if (Clazz == null) {
                if (wBasePOList.get(0) != null) {
                    Clazz = wBasePOList.get(0).getClass();
                    setPOConfig(Clazz);
                } else {
                    wErrorCode.set(ExceptionTypes.Parameter.getValue());
                    return wResult;
                }
            }


            List<Integer> wIDList =
                    wBasePOList.stream().filter(p -> p.ID > 0).map(p -> p.ID).distinct().collect(Collectors.toList());

            if (wIDList == null || wIDList.size() == 0) {
                return wResult;
            }
            DBBasePO dbBasePO = POUtils.GetInstance().getDBBasePO(Clazz);
            if (dbBasePO != null && !dbBasePO.Active()) {
                wErrorCode.set(ExceptionTypes.Exception.getValue());
                return wResult;
            }

            if (wActive != 1)
                wActive = 2;

            Map<String, Object> wParams = new HashMap<>();

            wParams.put("EditorID", wLoginUser.getID());
            wParams.put("EditTime", Calendar.getInstance());
            wParams.put("Active", wActive);


            Map<String, Object> wConditionData = new HashMap<>();

            wResult = this.Update(wParams, wConditionData, " AND ID  in (" + StringUtils.Join(",", wIDList) + ")");

        } catch (Exception ex) {
            log.error("ActivePOList", ex);
            wErrorCode.set(ExceptionTypes.DBSQL.getValue());
        }
        return wResult;
    }


    public <T extends BasePO> List<T> SelectPOList(
            BaseUser wLoginUser, Map<String, Object> wParams, Class<T> wClazz, Pagination wPagination,
            OutResult<Integer> wErrorCode) {
        List<T> wResult = SelectPOList(wLoginUser, null, null, wParams, wClazz, wPagination,
                wErrorCode);
        CacheUtils.SetData(wResult);
        this.SetItemList(wLoginUser, wResult, wErrorCode);
        return wResult;
    }


    public <T extends BasePO> List<T> SelectPOList(
            BaseUser wLoginUser, Map<String, Object> wParams, Class<T> wClazz,
            OutResult<Integer> wErrorCode) {
        List<T> wResult = SelectPOList(wLoginUser, null, null, wParams, wClazz, null,
                wErrorCode);
        CacheUtils.SetData(wResult);
        this.SetItemList(wLoginUser, wResult, wErrorCode);
        return wResult;
    }


    public <T extends BasePO> List<T> SelectPOList(
            BaseUser wLoginUser, Map<String, Object> wParams, Pagination wPagination,
            OutResult<Integer> wErrorCode) {
        return SelectPOList(wLoginUser, wParams, (Class<T>) Clazz, wPagination,
                wErrorCode);
    }


    public <T extends BasePO> void SetItemList(BaseUser wLoginUser, List<T> wResult, OutResult<Integer> wErrorCode) {

        if (wResult == null || wResult.size() == 0)
            return;
        try {
            Map<String, Object> wParams = new HashMap<>();

            List<DBJoinMultiSelectValue> wDBJoinMultiSelectList =
                    POUtils.GetInstance().getDBJoinMultiSelectValueList(wResult.get(0).getClass());

            if (wDBJoinMultiSelectList == null || wDBJoinMultiSelectList.size() == 0)
                return;
            List<Object> wValueList = new ArrayList<>();

            Object obj = null;
            for (DBJoinMultiSelectValue dbJoinMultiSelectValue : wDBJoinMultiSelectList) {

                wValueList.clear();
                for (T t : wResult) {
                    obj = dbJoinMultiSelectValue.MainField.get(t);
                    if (StringUtils.IsEmptyCondition(obj))
                        continue;
                    wValueList.add(obj);
                }
                if (wValueList.size() == 0)
                    continue;
                wParams.put(dbJoinMultiSelectValue.OutTableField, wValueList);
                List<? extends BasePO> wItemList =
                        ORMUtils.GetPoService(dbJoinMultiSelectValue.ItemClazz).SelectPOList(wLoginUser, wParams,
                                wErrorCode);

                if (wErrorCode.Result != 0)
                    break;
                if (wItemList == null || wItemList.size() == 0)
                    continue;

                Map<Object, ? extends List<? extends BasePO>> wItemListMap =
                        wItemList.stream().collect(Collectors.groupingBy(p -> {
                            try {
                                return dbJoinMultiSelectValue.JoinViewField.get(p);
                            } catch (IllegalAccessException e) {
                                throw new RuntimeException(e);
                            }
                        }));
                for (T t : wResult) {
                    obj = dbJoinMultiSelectValue.MainField.get(t);
                    if (StringUtils.IsEmptyCondition(obj))
                        continue;
                    if (wItemListMap.containsKey(obj))
                        dbJoinMultiSelectValue.ItemListField.set(t, wItemListMap.get(obj));
                }

            }

        } catch (Exception ex) {
            log.error("SetItemList", ex);
            wErrorCode.set(ExceptionTypes.DBSQL.getValue());
        }
    }


    public <T extends BasePO> List<T> SelectPOList(BaseUser wLoginUser, List<Integer> wIDList,
                                                   Map<String, Object> wParams, Class<T> wClazz,
                                                   Pagination wPagination,
                                                   OutResult<Integer> wErrorCode) {
        return SelectPOList(wLoginUser, wIDList, null, wParams, wClazz, wPagination, wErrorCode);
    }

    public <T extends BasePO> List<T> SelectPOList(BaseUser wLoginUser, List<String> wCodeList,
                                                   Map<String, Object> wParams,
                                                   Pagination wPagination,
                                                   OutResult<Integer> wErrorCode) {
        return (List<T>) SelectPOList(wLoginUser, null, wCodeList, wParams, Clazz, wPagination, wErrorCode);
    }

    public <T extends BasePO> List<T> SelectPOList(BaseUser wLoginUser, List<Integer> wIDList, List<String> wCodeList,
                                                   Pagination wPagination,
                                                   OutResult<Integer> wErrorCode) {
        return (List<T>) SelectPOList(wLoginUser, wIDList, wCodeList, new HashMap<>(), Clazz, wPagination, wErrorCode);
    }

    public <T extends BasePO> List<T> SelectPOList(BaseUser wLoginUser, List<Integer> wIDList, List<String> wCodeList,
                                                   Map<String, Object> wParams, Pagination wPagination,
                                                   OutResult<Integer> wErrorCode) {
        return (List<T>) SelectPOList(wLoginUser, wIDList, wCodeList, wParams, Clazz, wPagination, wErrorCode);
    }


    public <T extends BasePO> List<T> SelectPOList(
            BaseUser wLoginUser, List<Integer> wIDList, List<String> wCodeList, Map<String, Object> wParams,
            Class<T> wClazz,
            Pagination wPagination,
            OutResult<Integer> wErrorCode) {
        List<T> wResult = new ArrayList<>();
        wErrorCode.set(0);
        try {
            if (wClazz == null) {
                wErrorCode.set(ExceptionTypes.Parameter.getValue());
                return wResult;
            }
            if (wPagination == null)
                wPagination = Pagination.getMaxSize(Clazz);
            if (wIDList == null)
                wIDList = new ArrayList<>();
            wIDList.removeIf(p -> p <= 0);

            DBBasePO dbBasePO = POUtils.GetInstance().getDBBasePO(wClazz);
            /**
             * 获取字段结构中所有的本表字段
             */
            List<DBFieldValue> wDBFieldValueList = POUtils.GetInstance().getDBField(
                    dbBasePO.TableAsName(), wClazz, dbBasePO, true);
            /**
             * 获取字段结构中所有的Join关联字段
             */
            List<DBJoinValue> wDBJoinValueList = POUtils.GetInstance().getDBJoin(wClazz, dbBasePO);
            /**
             * 获取字段结构中所有的查询条件
             */
            List<DBConditionValue> wDBConditionValueList = POUtils.GetInstance().getDBCondition(wClazz, dbBasePO);


            //剔除wDBJoinValueList中与主表字段重复的字段
            wDBJoinValueList.removeIf(p -> wDBFieldValueList.stream().anyMatch(q -> q.viewName.equals(p.viewName)));
            //将wDBFieldValueList变更为 t.xx as xx  若相同 去除 as

            /**
             * 查询字段集合
             */
            List<String> wSelectFieldList = new ArrayList<>();

            for (DBFieldValue wDBFieldValue : wDBFieldValueList) {
                //将本表字段添加到查询字段中 并根据设置 生成查询字段sql  如 t.Name、t.ID as TID 等
                wSelectFieldList.add(wDBFieldValue.CreateSelectField());
                wDBFieldValue.SetDBConditionValueConfig(wDBConditionValueList);
            }
            /**
             * 数据表sql语句集合
             */
            List<String> wTableStringList = new ArrayList<>();

            wTableStringList.add(StringUtils.Format(" from {0} as {1} ", getTableName(dbBasePO.TableName()),
                    dbBasePO.TableAsName()));
            /**
             * 关联表列表
             */
            Map<String, DBJoinValue> wTableJoinList = POUtils.GetInstance().GetDBJoinValueMap(
                    wDBJoinValueList, wSelectFieldList, wDBConditionValueList);

            //创建查询条件语句
            List<String> wConditionList = POUtils.GetInstance().CreateConditionStringList(
                    wClazz, wDBConditionValueList, wParams, wErrorCode);

            if (wErrorCode.Result != 0) {
                return wResult;
            }

            if (wIDList.size() > 0) {
                if (wConditionList.size() > 0) {
                    wConditionList.add(0, StringUtils.Format(" {0}.ID IN ({1}) ",
                            dbBasePO.TableAsName(), StringUtils.Join(",", wIDList)));
                } else {
                    wConditionList.add(StringUtils.Format(" {0}.ID IN ({1}) ",
                            dbBasePO.TableAsName(), StringUtils.Join(",", wIDList)));
                }
            }

            if (wCodeList != null && wCodeList.size() > 0) {
                if (wConditionList.size() > 0) {
                    wConditionList.add(0, StringUtils.Format(" {0}.Code IN (''{1}'') ",
                            dbBasePO.TableAsName(), StringUtils.Join("','", wCodeList)));
                } else {
                    wConditionList.add(StringUtils.Format(" {0}.Code IN (''{1}'') ",
                            dbBasePO.TableAsName(), StringUtils.Join("','", wCodeList)));
                }
            }

            //填充关联表语句
            this.AddTableStringList(wTableStringList, wTableJoinList);
            String wSQL = "";

            if (wConditionList.size() > 0) {
                wSQL = StringUtils.Format(" select {0} {1} where    {2} ",
                        StringUtils.Join(" , ", wSelectFieldList), StringUtils.Join(" ", wTableStringList),
                        wConditionList.size() > 0 ? StringUtils.Join(" and ", wConditionList) : "");
            } else {
                wSQL = StringUtils.Format(" select {0} {1} ",
                        StringUtils.Join(" , ", wSelectFieldList), StringUtils.Join(" ", wTableStringList));
            }

            //wResult = this.QueryForList(wSQL, wParams, wPagination, wClazz);

            List<Map<String, Object>> wQueryResultList = this.QueryForList(wSQL, wParams, wPagination, this.TableName
                    , this.GetCutTableName(wPagination.IsDesc()));

            for (Map<String, Object> wReader : wQueryResultList) {
                for (DBFieldValue wDBFieldValue : wDBFieldValueList) {
                    wDBFieldValue.setValue(wReader);
                }
                for (DBJoinValue wDBJoinValue : wDBJoinValueList) {
                    wDBJoinValue.setValue(wReader);
                }
            }

            wResult = JSON.parseArray(StringUtils.toJSONString(wQueryResultList), wClazz);

        } catch (Exception ex) {
            log.error("SelectPO", ex);
            wErrorCode.set(ExceptionTypes.DBSQL.getValue());
        }
        return wResult;
    }

    public <T extends BasePO> List<T> SelectPOList(
            BaseUser wLoginUser, List<Integer> wIDList,
            Pagination wPagination,
            OutResult<Integer> wErrorCode) {
        List<T> wResult = new ArrayList<>();
        wErrorCode.set(0);
        try {
            if (Clazz == null) {
                wErrorCode.set(ExceptionTypes.Logic.getValue());
                return wResult;
            }

            wResult = (List<T>) SelectPOList(wLoginUser, wIDList, null, new HashMap<>(), Clazz, wPagination,
                    wErrorCode);
        } catch (Exception ex) {
            log.error("SelectPO", ex);
            wErrorCode.set(ExceptionTypes.DBSQL.getValue());
        }
        return wResult;
    }

    public <T extends BasePO> T SelectPO(BaseUser wLoginUser, Map<String, Object> wParams, Class<T> wClazz,
                                         OutResult<Integer> wErrorCode) {
        if (wParams == null || wParams.size() == 0) {
            wErrorCode.Result = ExceptionTypes.Parameter.getValue();
            return CreateInstance(wClazz);
        }
        List<T> wList = this.SelectPOList(wLoginUser, wParams, wClazz, Pagination.getNewMaxSize(), wErrorCode);
        if (wList != null && wList.size() > 0)
            return wList.get(0);
        return CreateInstance(wClazz);
    }


    public <T extends BasePO> T CreateInstance(Class<T> wClazz) {
        if (wClazz == null)
            return null;
        try {
            return wClazz.newInstance();
        } catch (Exception e) {
            log.info("实例化T失败{}", wClazz.getSimpleName());
        }
        return null;
    }


    public <T extends BasePO> T SelectPO(BaseUser wLoginUser, Map<String, Object> wParams,
                                         OutResult<Integer> wErrorCode) {

        return this.SelectPO(wLoginUser, wParams, (Class<T>) Clazz, wErrorCode);
    }

    public <T extends BasePO> T SelectPO(BaseUser wLoginUser, int wID, String wCode, Class<T> wClazz,
                                         OutResult<Integer> wErrorCode) {


        if (wID <= 0 && StringUtils.isEmpty(wCode)) {
            wErrorCode.Result = ExceptionTypes.Parameter.getValue();
            return CreateInstance(wClazz);
        }
        Map<String, Object> wParams = new HashMap<>();
        if (wID > 0) {
            wParams.put("ID", wID);
        }
        if (StringUtils.isNotEmpty(wCode)) {
            wParams.put("Code", wCode);
        }
        return this.SelectPO(wLoginUser, wParams, wClazz, wErrorCode);
    }

    public <T extends BasePO> T SelectPO(BaseUser wLoginUser, int wID, String wCode, OutResult<Integer> wErrorCode) {

        return this.SelectPO(wLoginUser, wID, wCode, (Class<T>) Clazz, wErrorCode);
    }


    /**
     * 根据关联表集合生成关联表语句 并加入到关联表语句列表中
     *
     * @param wTableStringList 关联表语句列表
     * @param wTableJoinList   关联表集合
     */
    private void AddTableStringList(List<String> wTableStringList, Map<String, DBJoinValue> wTableJoinList) {
        List<DBJoinValue> wDistinctTableJoinList = wTableJoinList.values().stream().sorted(
                (o1, o2) -> o1.JoinIndex - o2.JoinIndex).collect(Collectors.toList());

        for (DBJoinValue wDBJoinValue : wDistinctTableJoinList) {

            if (wDBJoinValue == null) continue;
            if (StringUtils.isEmpty(wDBJoinValue.tableName) || StringUtils.isEmpty(wDBJoinValue.tableAsName) ||
                    wDBJoinValue.ConditionalJoin == null || wDBJoinValue.ConditionalJoin.size() == 0) {
                continue;
            }
            wDBJoinValue.ConditionalJoin.removeIf(p -> StringUtils.isEmpty(p));
            if (wDBJoinValue.ConditionalJoin.size() == 0) continue;

            wTableStringList.add(StringUtils.Format(" {0} join {1} as {2} on ( {3} ) ", wDBJoinValue.getJoinMode(),
                    wDBJoinValue.Schemas.getTBName(SQLType, wDBJoinValue.tableName), wDBJoinValue.tableAsName,
                    StringUtils.Join(" and ", wDBJoinValue.ConditionalJoin)));
        }
    }


    protected List<String> SelectTableNames(String wSCHEMA, String wTablePrefix) {
        List<String> wResult = new ArrayList<String>();
        String wSQL = StringUtils.Format("SELECT TABLE_NAME FROM information_schema.tables WHERE TABLE_SCHEMA=''{0}''" +
                " and TABLE_NAME LIKE ''{1}'%'", wSCHEMA, wTablePrefix);

        List<Map<String, Object>> wQueryResultList = this.queryForList(wSQL, new HashMap<String, Object>());

        for (Map<String, Object> wReader : wQueryResultList) {
            wResult.add(StringUtils.parseString(wReader.get("TABLE_NAME")));
        }
        wResult = wResult.stream().distinct().collect(Collectors.toList());
        return wResult;
    }

    protected boolean IsExitTable(String wSCHEMA, String wTableName) {
        boolean wResult = false;
        String wSQL = StringUtils.Format("SELECT count(*) as ItemCount FROM information_schema.tables WHERE " +
                "TABLE_SCHEMA=''{0}'' and TABLE_NAME = ''{1}''", wSCHEMA, wTableName);

        List<Map<String, Object>> wQueryResultList = this.queryForList(wSQL, new HashMap<String, Object>());

        for (Map<String, Object> wReader : wQueryResultList) {
            wResult = StringUtils.parseInt(wReader.get("ItemCount")) > 0;
        }
        return wResult;
    }


    protected List<String> QueryTableStruct(DBEnumType wDBEnumType, String wTableName, String wDBName) {
        List<String> wResult = new ArrayList<String>();
        switch (wDBEnumType) {
            case Default:
            case MySQL:
                wResult = QueryMysqlTableStruct(wTableName, wDBName);
                break;
            case SQLServer:
                wResult = QuerySqlServerTableStruct(wTableName, wDBName);
                break;
            case Oracle:
                break;
            case Access:
                break;
            default:
                break;
        }
        return wResult;

    }

    /// <summary>
    ///
    /// </summary>
    /// <param name="wTableName"></param>
    /// <param name="wDBName"></param>
    /// <returns></returns>
    protected List<String> QueryMysqlTableStruct(String wTableName, String wDBName) {
        List<String> wResult = new ArrayList<String>();

        String wSQL = StringUtils.Format("select COLUMN_NAME AS Name from information_schema.COLUMNS where " +
                "TABLE_SCHEMA = ''{0}'' and TABLE_NAME = ''{1}''", wDBName, wTableName);

        List<Map<String, Object>> wQueryResultList = this.queryForList(wSQL, new HashMap<String, Object>());
        for (Map<String, Object> wReader : wQueryResultList) {
            if (!wReader.containsKey("Name") || wResult.contains(wReader.get("Name")))
                continue;
            wResult.add(StringUtils.parseString(wReader.get("Name")));
        }
        return wResult;
    }

    /// <summary>
    ///
    /// </summary>
    /// <param name="wTableName"></param>
    /// <param name="wDBName"></param>
    /// <returns></returns>
    protected List<String> QuerySqlServerTableStruct(String wTableName, String wDBName) {
        List<String> wResult = new ArrayList<String>();
        String wSQL = StringUtils.Format(" Select Name from SysColumns Where id = Object_Id(''{0}''.dbo.''{1}'')",
                wDBName, wTableName);


        List<Map<String, Object>> wQueryResultList = this.queryForList(wSQL, null);
        for (Map<String, Object> wReader : wQueryResultList) {
            if (!wReader.containsKey("Name") || wResult.contains(wReader.get("Name")))
                continue;
            wResult.add(StringUtils.parseString(wReader.get("Name")));
        }

        return wResult;
    }

    protected void batchUpdate(String wSQL, SqlParameterSource[] wParams) {
        try {
            shrisJdbcTemplate.batchUpdate(wSQL, wParams);
        } catch (Exception ex) {
            log.error("batchUpdate", ex);
        }
    }

}
